//! Integration tests for AI Test Platform
//! 
//! These tests verify the core functionality of the platform.

use ai_test_platform::{
    init, platform_info,
    models::{
        testcase::{TestCase, TestCasePath, ITestCase},
        config::TestConfig,
        step::{StepResult, StepType},
        request::{HttpRequest, HttpMethod},
    },
    plugins::builtin::BuiltinPluginManager,
    protocols::ProtocolManager,
    storage::{TestResultQuery, MetricsQuery},
};
use chrono::Utc;
use tokio;
use uuid::Uuid;

#[tokio::test]
async fn test_platform_initialization() {
    let result = init().await;
    assert!(result.is_ok(), "Platform should initialize successfully");
}

#[test]
fn test_platform_info() {
    let info = platform_info();
    assert_eq!(info.name, "ai-test-platform");
    assert!(!info.version.is_empty());
    assert!(!info.description.is_empty());
}

#[test]
fn test_test_config_creation() {
    let config = TestConfig::new("test_config".to_string())
        .with_base_url("https://api.example.com".to_string())
        .with_request_timeout(30.0)
        .with_ssl_verify(true);
    
    assert_eq!(config.name, "test_config");
    assert_eq!(config.base_url, Some("https://api.example.com".to_string()));
    assert_eq!(config.request_timeout, Some(30.0));
    assert!(config.verify);
}

#[test]
fn test_test_case_creation() {
    let config = TestConfig::new("test_case".to_string());
    let test_case = TestCase::new(config);
    
    assert_eq!(test_case.config.name, "test_case");
    assert_eq!(test_case.step_count(), 0);
    assert!(test_case.is_enabled());
    assert!(test_case.validate().is_err()); // Should fail because no steps
}

#[test]
fn test_http_request_creation() {
    let request = HttpRequest::get("https://api.example.com/users".to_string())
        .header("Authorization".to_string(), "Bearer token123".to_string())
        .timeout(30.0);
    
    assert_eq!(request.method, HttpMethod::GET);
    assert_eq!(request.url, "https://api.example.com/users");
    assert_eq!(request.headers.get("Authorization"), Some(&"Bearer token123".to_string()));
    assert_eq!(request.timeout, Some(30.0));
}

#[test]
fn test_step_result_creation() {
    let id = Uuid::new_v4();
    let result = StepResult::new(id, "test_step".to_string(), StepType::Request)
        .success()
        .with_elapsed(100)
        .with_data(serde_json::json!({"status": "ok"}));
    
    assert_eq!(result.id, id);
    assert_eq!(result.name, "test_step");
    assert_eq!(result.step_type, StepType::Request);
    assert!(result.success);
    assert_eq!(result.elapsed, 100);
    assert!(result.data.is_some());
}

#[tokio::test]
async fn test_builtin_plugin_manager() {
    let manager = BuiltinPluginManager::new();
    
    // Should have default plugins registered
    assert!(manager.plugin_count() > 0);
    
    // Should have HTTP plugin
    assert!(manager.get_plugin("http").is_some());
    
    // Should have database plugin
    assert!(manager.get_plugin("database").is_some());
    
    // Should have utils plugin
    assert!(manager.get_plugin("utils").is_some());
    
    // Should have validation plugin
    assert!(manager.get_plugin("validation").is_some());
    
    // Test plugin function call
    let result = manager.call_function("utils", "now", &[]).await;
    assert!(result.is_ok());
}

#[tokio::test]
async fn test_protocol_manager() {
    let manager = ProtocolManager::new();
    
    // Should have default protocols registered
    let protocols = manager.list_protocols();
    assert!(protocols.contains(&"http"));
    assert!(protocols.contains(&"websocket"));
    assert!(protocols.contains(&"grpc"));
    assert!(protocols.contains(&"graphql"));
    
    // Test protocol operations
    let http_ops = manager.get_protocol_operations("http");
    assert!(http_ops.is_some());
    let ops = http_ops.unwrap();
    assert!(ops.contains(&"request".to_string()));
    assert!(ops.contains(&"get".to_string()));
    assert!(ops.contains(&"post".to_string()));
}

#[test]
fn test_test_result_query_builder() {
    let start_time = Utc::now();
    let end_time = start_time + chrono::Duration::hours(1);
    
    let query = TestResultQuery::new()
        .with_success(true)
        .with_time_range(start_time, end_time)
        .with_limit(100)
        .sort_by("start_time".to_string(), true);
    
    assert_eq!(query.success, Some(true));
    assert_eq!(query.start_time, Some(start_time));
    assert_eq!(query.end_time, Some(end_time));
    assert_eq!(query.limit, Some(100));
    assert_eq!(query.sort_by, Some("start_time".to_string()));
    assert!(query.sort_desc);
}

#[test]
fn test_metrics_query_builder() {
    let start = Utc::now();
    let end = start + chrono::Duration::hours(1);
    
    let query = MetricsQuery::new(start, end)
        .with_metrics(vec!["success_rate".to_string()])
        .group_by("test_type".to_string());
    
    assert_eq!(query.start_time, start);
    assert_eq!(query.end_time, end);
    assert_eq!(query.metrics, vec!["success_rate".to_string()]);
    assert_eq!(query.group_by, Some("test_type".to_string()));
}

#[test]
fn test_test_case_path() {
    let test_case_path = TestCasePath::new("tests/fixtures/sample_test.json");
    assert_eq!(test_case_path.name(), "sample_test");
    assert_eq!(test_case_path.path(), Some("tests/fixtures/sample_test.json"));
}

#[test]
fn test_test_case_metadata() {
    let config = TestConfig::new("test_case".to_string());
    let mut test_case = TestCase::new(config);
    
    // Test tag management
    test_case.add_tag("smoke".to_string());
    test_case.add_tag("api".to_string());
    
    assert_eq!(test_case.tags().len(), 2);
    assert!(test_case.tags().contains(&"smoke".to_string()));
    assert!(test_case.tags().contains(&"api".to_string()));
    
    test_case.remove_tag("smoke");
    assert_eq!(test_case.tags().len(), 1);
    assert!(!test_case.tags().contains(&"smoke".to_string()));
}

#[test]
fn test_http_method_parsing() {
    use std::str::FromStr;
    
    assert_eq!(HttpMethod::from_str("GET").unwrap(), HttpMethod::GET);
    assert_eq!(HttpMethod::from_str("post").unwrap(), HttpMethod::POST);
    assert_eq!(HttpMethod::from_str("PUT").unwrap(), HttpMethod::PUT);
    assert!(HttpMethod::from_str("INVALID").is_err());
}

#[test]
fn test_json_serialization() {
    use ai_test_platform::models::JsonSerializable;
    
    let config = TestConfig::new("test".to_string());
    
    // Test JSON serialization
    let json = config.to_json().unwrap();
    assert!(json.contains("test"));
    
    // Test JSON deserialization
    let parsed: TestConfig = TestConfig::from_json(&json).unwrap();
    assert_eq!(parsed.name, "test");
}

#[test]
fn test_yaml_serialization() {
    use ai_test_platform::models::YamlSerializable;
    
    let config = TestConfig::new("test".to_string());
    
    // Test YAML serialization
    let yaml = config.to_yaml().unwrap();
    assert!(yaml.contains("test"));
    
    // Test YAML deserialization
    let parsed: TestConfig = TestConfig::from_yaml(&yaml).unwrap();
    assert_eq!(parsed.name, "test");
}

#[test]
fn test_timestamp_helpers() {
    use ai_test_platform::models::{now, format_timestamp, parse_timestamp};
    
    let timestamp = now();
    let formatted = format_timestamp(&timestamp);
    let parsed = parse_timestamp(&formatted).unwrap();
    
    // Allow for small differences due to precision
    let diff = (timestamp - parsed).num_milliseconds().abs();
    assert!(diff < 1000); // Less than 1 second difference
}
